package com.mdp.workflow.comm.tools;

import com.mdp.core.SpringUtils;
import com.mdp.core.utils.ObjectTools;
import com.mdp.safe.client.utils.LoginUtils;
import com.mdp.workflow.biz.ru.entity.ProcinstNodeInfo;
import com.mdp.workflow.biz.ru.service.ProcinstNodeInfoService;
import com.mdp.workflow.bus.candidate.TaskCandidateInvoker;
import com.mdp.workflow.comm.dict.ProcinstConstants;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.api.variable.VariableContainer;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.TaskInfo;

import java.util.*;

/**
 * Flowable 相关的工具方法
 *
 *@author 唛盟开源9哥
 */
public class FlowableUtils {

    // ========== User 相关的工具方法 ==========

    public static void setAuthenticatedUserId(String userid) {
        Authentication.setAuthenticatedUserId( userid );
    }

    public static void clearAuthenticatedUserId() {
        Authentication.setAuthenticatedUserId(null);
    }

    static ProcinstNodeInfoService  procinstNodeInfoService;


    public static ProcinstNodeInfoService getProcinstNodeInfoService() {
        if(procinstNodeInfoService==null){
            procinstNodeInfoService= SpringUtils.getBean(ProcinstNodeInfoService.class);
        }
        return procinstNodeInfoService;
    }

    public static String getTenantId() {
        String tenantId = LoginUtils.getCurrentUserInfo().getBranchId();
        return ObjectTools.isEmpty(tenantId)?"platform-branch-001":tenantId;
    }

    // ========== Execution 相关的工具方法 ==========

    /**
     * 格式化多实例（并签、或签）的 collectionVariable 变量（多实例对应的多审批人列表）
     *
     * @param activityId 活动编号
     * @return collectionVariable 变量
     */
    public static String formatExecutionCollectionVariable(String activityId) {
        return activityId + "_assignees";
    }

    /**
     * 格式化多实例（并签、或签）的 collectionElementVariable 变量（当前实例对应的一个审批人）
     *
     * @param activityId 活动编号
     * @return collectionElementVariable 变量
     */
    public static String formatExecutionCollectionElementVariable(String activityId) {
        return activityId + "_assignee";
    }

    // ========== ProcessInstance 相关的工具方法 ==========

    public static String getProcessInstanceStatus(ProcessInstance processInstance) {
        return getProcessInstanceStatus(processInstance.getProcessVariables());
    }

    public static String getProcessInstanceStatus(HistoricProcessInstance processInstance) {
        return getProcessInstanceStatus(processInstance.getProcessVariables());
    }

    /**
     * 获得流程实例的状态
     *
     * @param processVariables 流程实例的 variables
     * @return 状态
     */
    private static String getProcessInstanceStatus(Map<String, Object> processVariables) {
        return (String) processVariables.get(ProcinstConstants.PROCINST_STATUS);
    }

    /**
     * 获得流程实例的表单
     *
     * @param processInstance 流程实例
     * @return 表单
     */
    public static Map<String, Object> getProcessInstanceFormVariable(HistoricProcessInstance processInstance) {
        Map<String, Object> formVariables = new HashMap<>(processInstance.getProcessVariables());
        filterProcessInstanceFormVariable(formVariables);
        return formVariables;
    }

    /**
     * 过滤流程实例的表单
     *
     * 为什么要过滤？目前使用 processVariables 存储所有流程实例的拓展字段，需要过滤掉一部分的系统字段，从而实现表单的展示
     *
     * @param processVariables 流程实例的 variables
     * @return 过滤后的表单
     */
    public static Map<String, Object> filterProcessInstanceFormVariable(Map<String, Object> processVariables) {
        processVariables.remove(ProcinstConstants.PROCINST_STATUS);
        return processVariables;
    }

    /**
     * 获得流程实例的发起用户选择的审批人列表 Set<String>
     *
     * @param execution 流程执行实例
     * @return 发起用户选择的审批人集合 Set<String>
     */
    @SuppressWarnings("unchecked")
    public static Set<String> getStartUserSelectAssignees(DelegateExecution execution) {
        List<ProcinstNodeInfo> nodeInfos=getProcinstNodeInfoService().getNodeInfosFromCache(execution.getProcessInstanceId());
        if(nodeInfos==null||nodeInfos.size()==0){
            return new LinkedHashSet<>();
        }else{
            Optional<ProcinstNodeInfo> optional=nodeInfos.stream().filter(k->k.getActId().equals(execution.getCurrentActivityId())).findAny();
            if(optional.isPresent()){
                ProcinstNodeInfo nodeInfo=optional.get();
                TaskCandidateInvoker taskCandidateInvoker=SpringUtils.getBean(TaskCandidateInvoker.class);
                return taskCandidateInvoker.calculateUsers(execution,nodeInfo.getStrategy(),nodeInfo.getStrategyParam());
            }else{
              return   new LinkedHashSet<>();
            }
        }
    }

    // ========== Task 相关的工具方法 ==========

    /**
     * 获得任务的状态
     *
     * @param task 任务
     * @return 状态
     */
    public static String getTaskStatus(TaskInfo task) {
        return (String) task.getTaskLocalVariables().get(ProcinstConstants.TASK_STATUS);
    }

    /**
     * 获得任务的审批原因
     *
     * @param task 任务
     * @return 审批原因
     */
    public static String getTaskReason(TaskInfo task) {
        return (String) task.getTaskLocalVariables().get(ProcinstConstants.REASON);
    }

    /**
     * 获得任务的表单
     *
     * @param task 任务
     * @return 表单
     */
    public static Map<String, Object> getTaskFormVariable(TaskInfo task) {
        Map<String, Object> formVariables = new HashMap<>(task.getTaskLocalVariables());
        filterTaskFormVariable(formVariables);
        return formVariables;
    }

    /**
     * 过滤任务的表单
     *
     * 为什么要过滤？目前使用 taskLocalVariables 存储所有任务的拓展字段，需要过滤掉一部分的系统字段，从而实现表单的展示
     *
     * @param taskLocalVariables 任务的 taskLocalVariables
     * @return 过滤后的表单
     */
    public static Map<String, Object> filterTaskFormVariable(Map<String, Object> taskLocalVariables) {
        taskLocalVariables.remove(ProcinstConstants.TASK_STATUS);
        taskLocalVariables.remove(ProcinstConstants.REASON);
        return taskLocalVariables;
    }

    // ========== Expression 相关的工具方法 ==========

    public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) {
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
        assert processEngineConfiguration != null;
        ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
        assert expressionManager != null;
        Expression expression = expressionManager.createExpression(expressionString);
        return expression.getValue(variableContainer);
    }

}
